package com.lx.web;


import com.lx.core.annotation.Value;
import com.lx.util.LX;
import com.lx.core.LXLog;
import com.lx.core.annotation.Bean;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Bean(init = "init")
public class HttpServer {

    @Value("server.port:8080")
    private int port;

    public void init(final Servlet servlet) throws IOException {
        final ServerSocket server = new ServerSocket(port);//端口 和 最大连接 创建服务
        LXLog.info("监听端口:"+port);
        final ThreadPoolExecutor pool = new ThreadPoolExecutor(10, 1000, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());//创建连接池
        pool.execute(new Runnable() {
            @Override
            public void run() {
                while (true){
                    try {
                        final Socket accept = server.accept();//等待连接
                        pool.execute(new Runnable() {
                            @Override
                            public void run() {
                                servlet.doPost(accept);
                            }
                        });
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                }
            }
        });
    }


   public abstract static class Servlet {
        public abstract Response doPost(Request request) throws InvocationTargetException, IllegalAccessException, Exception;
        public void doPost(Socket accept){
            BufferedOutputStream bis=null;
            try {
                bis = new BufferedOutputStream(accept.getOutputStream());
                Response o = doPost(new Request(accept));
                String responseHeader="HTTP/1.1 "+o.code+" \r\nContent-Type: application/json; charset=utf-8\r\n\r\n";
                inToOut(new ByteArrayInputStream(responseHeader.getBytes(StandardCharsets.UTF_8)),bis);
                inToOut(new ByteArrayInputStream(o.data.toString().getBytes(StandardCharsets.UTF_8)),bis);
            }catch (Exception e){
                LXLog.error("调用接口错误!",e);
                String responseHeader="HTTP/1.1 500 \r\nContent-Type: text/html; charset=utf-8\r\n\r\n";
                try {
                    inToOut(new ByteArrayInputStream(responseHeader.getBytes(StandardCharsets.UTF_8)),bis);
                    inToOut(new ByteArrayInputStream(e.toString().getBytes(StandardCharsets.UTF_8)),bis);
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }finally {
                if (bis != null){
                    try {
                        bis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        //将输入流转入输出流
        private static void inToOut(InputStream is, OutputStream bis) throws IOException {
            byte[] charBuf = new byte[1024];
            int mark;
            BufferedInputStream isr = new BufferedInputStream(is);
            while ((mark = isr.read(charBuf)) != -1) {
                if (mark < charBuf.length){
                    byte[] o = new byte[mark];
                    System.arraycopy(charBuf,0,o,0,mark);
                    bis.write(o);
                    break;
                }else{
                    bis.write(charBuf);
                }
            }
        }

    }
    public static class Request{
        private String url;
        private Map<String,String> parameter;
        private String body;
        private String address;
        private String requestType;

        public String getUrl() {
            return url;
        }

        public Map<String, String> getParameter() {
            return parameter;
        }

        public String getBody() {
            return body;
        }

        public String getAddress() {
            return address;
        }

        public String getRequestType() {
            return requestType;
        }

        public Request(Socket socket) throws IOException {
            StringBuilder builder = new StringBuilder();
            InputStreamReader isr = new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8);
            char[] charBuf = new char[1024];
            int mark;
            while ((mark = isr.read(charBuf)) != -1) {
                builder.append(charBuf, 0, mark);
                if (mark < charBuf.length) break;
            }
            if ("".equals(builder.toString())) return;
            String line = builder.substring(0, builder.indexOf("\r\n"));
            String[] lineArr = line.split("\\s");
            requestType = lineArr[0];
            url = URLDecoder.decode(lineArr[1]);
            parameter = toParamter(url);
            if (url.indexOf("?")!=-1){
                url = url.substring(0,url.indexOf("?"));
            }
            body = builder.substring(builder.indexOf("\r\n\r\n")+4);
            address = socket.getInetAddress().getHostAddress();;
        }

        //说明: 解析入参
        /**{ ylx } 2021/9/12 0:02 */
        private Map<String, String> toParamter(String url) {
            String data = url.substring(url.indexOf("?")+1);
            Map<String, String> map = new HashMap<>();
            if (LX.isNotEmpty(data)){
                Arrays.asList(data.split("&")).forEach(kv->{
                    if (kv.indexOf("=")>0 && kv.length()>kv.indexOf("=")+1){
                        map.put(kv.substring(0,kv.indexOf("=")),kv.substring(kv.indexOf("=")+1));
                    }
                });
            }
            return map;
        }

        @Override
        public String toString() {
            return "{" +
                    "url='" + url + '\'' +
                    ", parameter=" + parameter +
                    ", body='" + body + '\'' +
                    ", address='" + address + '\'' +
                    '}';
        }
    }

    public static class Response{
        private String code;
        private Object data;

        public Response(String code, Object data) {
            if (code == null){
                code = "200";
            }
            if (data == null){
                data = "{}";
            }
            this.code = code;
            this.data = data;
        }

        @Override
        public String toString() {
            return "Response{" +
                    "code='" + code + '\'' +
                    ", data=" + data +
                    '}';
        }
    }

}
